Spell out the ini files, sys_temp_dir and xdebug.mode of the current process on spawned PHP command lines - #6401
Open
phpstan-bot wants to merge 1 commit into
Conversation
…ent process on spawned PHP command lines - Add `PHPStan\Process\InheritedPhpConfig`, which resolves the PHP CLI options a child process needs to run with the PHP configuration of the process starting it: `-n` when this process read no additional ini files, `-c` for the loaded php.ini, `-d sys_temp_dir=` and `-d xdebug.mode=`. - `ProcessHelper::getWorkerCommand()` builds the worker command from it instead of passing `-c php_ini_loaded_file()` alone, so a worker no longer re-reads the ini scan directory the main process was started without, and no longer loses an `xdebug.mode` set on the command line. - `TurboProcessRestarter` had the same gap on the process it re-executes - extracted `resolveRestartArgs()` and prepended the inherited options there, so `php -d xdebug.mode=off vendor/bin/phpstan` no longer restarts into a process with Xdebug active again (and `-d sys_temp_dir=` no longer gets lost across the restart, which only the worker command used to repeat). - Same fix for the two other PHP processes PHPStan starts: the PHPStan Pro process in `FixerApplication` (which passed no `-c` at all) and the phar of each `bisect` step in `BisectCommand`. - `phpstan diagnose` prints the resulting php options for spawned workers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
php -d xdebug.mode=off vendor/bin/phpstanturned Xdebug off for the main process only. Every parallel worker loaded Xdebug again from the ini scan directory in whatever mode the ini says, so the analysis ran under an active Xdebug — several times slower, with nothing on screen saying so.The cause is that a child process inherits the environment but nothing of the command line. The worker command repeated
-c <php.ini>and stopped there:-dentries were dropped, and the ini scan directory was read again even when the spawning process had not read it.Changes
src/Process/InheritedPhpConfig.php: resolves the PHP CLI options a child process needs to run with the PHP configuration of the process starting it —-nwhen this process read no additional ini files,-cfor the loaded php.ini,-d sys_temp_dir=and-d xdebug.mode=. Xdebug's mode is read withini_get(), falling back toget_cfg_var()for a PHP that has no Xdebug loaded and therefore no registered directive.src/Process/ProcessHelper.php: the worker command (parallel analysis workers and the fixer worker) is built from those options instead of-c php_ini_loaded_file()alone.sys_temp_dirmoved into the shared class.src/Turbo/TurboProcessRestarter.php: the same gap on the process it re-executes. The command line assembly moved into a testableresolveRestartArgs()and now starts from the inherited options.src/Command/FixerApplication.php: the PHPStan Pro process, which passed no-cat all.src/Command/BisectCommand.php: each bisect step, which runs a full PHPStan phar of its own.src/Parallel/ForkParallelChecker.php:phpstan diagnoseprints the php options a spawned worker gets, next to the-dentries it already listed.bin/phpstan: requires the new file beforeTurboProcessRestarter::restartIfSuitable(), which runs before the autoloader.Probed and left alone:
ForkedProcess/ForkParallelChecker(a forked worker inherits the whole process, including its ini state, so there is nothing to repeat),LevelsTestCase(extension-developer test infrastructure, not a PHPStan run), andmemory_limiton the bisect child (the three other spawn sites forward it, butbisectdeliberately builds its analyse args from the user's own--memory-limitoption, so changing that is a separate decision).Root cause
The pattern is "PHP configuration a child process does not inherit".
PHP_INI_SCAN_DIRandPHPRC— what composer/xdebug-handler sets up for its persistent restart — travel in the environment and need no help. Everything given on the command line travels nowhere, and PHPStan starts four PHP processes:ProcessHelper::getWorkerCommand()-c <php.ini>,-d sys_temp_dir=TurboProcessRestarter::restartIfSuitable()-c <php.ini>FixerApplication(PHPStan Pro)BisectCommand(phar per step)Two consequences followed from that, and both are fixed by resolving the options in one place:
-dentries are dropped. Withxdebug.mode=offon the command line,XdebugHandlersees an inactive Xdebug and rightly does not restart, so noPHPRCis set up either and nothing else keeps Xdebug out of the children. Each worker then started with an active Xdebug, and — because the worker runsCommandHelper::begin()too — restarted itself through xdebug-handler, spawning another process per worker and losing thesys_temp_dir, OPcache and turbo-extension entries of the spawn in the process.php -n, or a-cpointing elsewhere, gave the child every extension and setting the main process was deliberately started without.-nnext to an explicit-cis what xdebug-handler's own standard restart does.sys_temp_diris the same bug seen from the other side: only the worker command repeated it, so a-d sys_temp_dir=was lost as soon asTurboProcessRestarterre-executed the main process.Test
tests/PHPStan/Process/InheritedPhpConfigTest.phptestResolveArgs()pins the resolved options for each combination of loaded/scanned ini files and Xdebug mode, including the empty string the ini parser makes ofxdebug.mode=off.testChildProcessRepeatsThePhpConfigurationOfItsParent()is the regression test for the report: it starts a real PHP process (as started,-d xdebug.mode=off,-n), which starts a child of its own with the resolved options, and compares the loaded ini file, whether additional ini files were scanned,xdebug.modeand the temp directory of the two. With the previous-c-only command line the-d xdebug.mode=offcase reportscoveragein the child against `` in the parent, and the-ncase reports the whole scanned ini set in the child against none in the parent. It needs no Xdebug installed to run.tests/PHPStan/Process/ProcessHelperTest.php::testWorkerCommandRepeatsThePhpConfigurationOfTheSpawningProcess()— the worker command starts with those options.tests/PHPStan/Turbo/TurboProcessRestarterTest.php— two tests forresolveRestartArgs(), covering the inherited options and the turbo extension entries.Fixes phpstan/phpstan#15189